home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Precos 4.97 Computer 2000
/
Precos 4.97 Computer 2000.iso
/
mac
/
Info
/
5Networking
/
3COM
/
3COMTFTP.EXE
/
TFTPFLS.EXE
/
3COMTFTP
/
EXE
/
IBMTOKEN.ASM
< prev
next >
Wrap
Assembly Source File
|
1992-01-06
|
59KB
|
2,065 lines
;*****************************************************************************;
;* *;
;* File: IBMTOKEN.ASM *;
;* Auth: Brian Fisher *;
;* Queens University *;
;* Computing and Communications Services *;
;* Rm 2-50 Dupuis Hall *;
;* Kingston Ontario *;
;* *;
;* Date: September 3 1989 *;
;* *;
;* Purp: Ethernet (3C501) packet driver for IBM Token Ring. This *;
;* driver uses the IBM LAN support program DIR interface. *;
;* The current implementation supports IP and ARP. *;
;* *;
;* (C) 1989 Queens University *;
;* Computing and Communications Services. This portion of *;
;* the program remains the property of Queens University. *;
;* *;
;*===========================================================================*;
;* Program Logic: *;
;* *;
;* IBMTOKEN extracts IP and ARP data from ethernet datagrams passed to *;
;* it by the ULP, makes any adjustments required, then builds a token *;
;* ring datagram and sends it out over the network. The process is *;
;* reversed when packets are received. IBMTOKEN supports token ring *;
;* source routing and functions in a bridged environment. *;
;* *;
;* The ULP uses Ethernet 'Blue Book' encapsulation. IBMTOKEN uses *;
;* 802.2 LLC format for transmission on token ring. The IBM (tm) *;
;* LAN Support Program is required. IBMTOKEN uses the DIR interface *;
;* to send/receive packets on token ring. *;
;* *;
;* IP packets do not require any modifications, and are sent 'as is.' *;
;* ARP packets have an 'hwr' field that must be changed fro 1h to 6h *;
;* during send_pkt, and changed back to 1h from 6h during _receive. *;
;* *;
;* The minimum size of an ethernet packet is 60 bytes (minus the 4 byte *;
;* ethernet checksum). Token ring has no lower limit. The ULP will *;
;* reject 'short' packets, so IBMTOKEN lies and tells it there are 60 *;
;* bytes. *;
;* *;
;* ARP packets are 28 bytes in length. The ULP rounds the size of a *;
;* packet up to 60 bytes, so there is extra data on the end of the ARP *;
;* packet. IBMTOKEN trims this off, because token ring hosts reject *;
;* 'too long' ARP packets. *;
;* *;
;* The minimum size of an ethernet packet is 60 bytes. The maximum *;
;* is 1514 bytes. The buffer sizes for token ring send/receive are *;
;* set to accomodate this. *;
;* *;
;* Source Routing: *;
;* *;
;* The ethernet entrenched logic of the ULP does not accomodate source *;
;* routing. IBMTOKEN provides a mechanism for source routing that is *;
;* transparent to the ULP. The RIF information associated with token *;
;* ring source addresses are placed in a cache. When the ULP sends to *;
;* that address, the RIF information is extracted from the cache and *;
;* used to route the packet to the target host. *;
;* *;
;* RIF Cache Logic: *;
;* *;
;* The cache logic uses an LRU algorithm. Each entry is time *;
;* stamped. If all the slots in the cache are being used, the oldest *;
;* entry (assumed to be the LRU) is replaced (bumped from the cache). *;
;* *;
;* If the ULP uses an address whose RIF has been bumped from the *;
;* cache, a mechanism exists to rediscover the source route. *;
;* IBMTOKEN attaches a phony RIF, with the broadcast bit set and *;
;* and empty route table. This packet travels to all rings. When *;
;* the foreign host responds, the RIF info is placed back in the *;
;* cache. Subsequent transmissions will use the rediscovered RIF. *;
;* *;
;* The size of the RIF cache should be set to handle the maximum *;
;* number of concurrent hosts. This will minimize the bumping *;
;* effect and minimize all rings broadcasts. *;
;* *;
;* I chose this algorithm so the ULP would not require any special *;
;* coding to work. It eliminates the need for special syncronization *;
;* of the ARP and RIF cache's. *;
;* *;
;*===========================================================================*;
;* *;
;* Revs: Sep 29 1989 Successful tests with TN3270, FTP, and FTPBIN.*;
;* B. Fisher Some fine tuning required. *;
;* *;
;* Oct 1 1989 Cleaning up code. Found bug that prevented *;
;* buffer1/buffer2..n copies from working. *;
;* *;
;* Oct 15 1989 Rearranged buffer sizes to accomodate Adapt I *;
;* *;
;* Nov 15 1989 Added missing popf at end of recv_complt *;
;* Fixed missing popf at end of recv_complt *;
;* *;
;* Nov 19 1989 Added marker to show interrupt activity *;
;* for debugging. *;
;* *;
;* Nov 20 1989 Add changes for Release 5 compatibility *;
;* *;
;* Nov 21 1989 Fix es/bx reversal at get_size *;
;* *;
;* Nov 22 1989 RIF not working because of confusion with *;
;* SA bit acquired via ARP and SA bit acquired *;
;* through Token Receive. Send_Pkt now looks *;
;* up all dest addresses in RIF table. *;
;* *;
;* Nov 23 1989 Have DEBUG mode report RIF table address when *;
;* get_multicast_ call made. *;
;* *;
;* Nov 28 1989 Add phony RIF to 'local' addresses so the *;
;* bridge will pass them on. ARP acquired HW *;
;* addresses need RIF to cross bridge. This is *;
;* done in send_pkt. *;
;* *;
;* Nov 29 1989 Fixed REPT macro in SA_blk so size of SA info *;
;* is correct. Didn't hurt function, however. *;
;* *;
;* Nov 29 1989 Clear broadcast bit in RIF before entry in *;
;* table. This prevents bridges from altering *;
;* existing route. FF,FF,FF,FF,FF,FF address *;
;* uses broadcast bit so ARP will work. *;
;* *;
;* Nov 29 1989 Predefined broadcast RIF entry direction bit *;
;* polarity reversal prevented broadcast from *;
;* going over the bridge. *;
;* *;
;* Version 1.A - Production Version released at Queens *;
;* *;
;* Jan 02 1990 Fix missing CLD in _receiver, shows up when *;
;* TOKREUI is used instead of Lan Support Pgm... *;
;* *;
;* Version 1.B *;
;* Jan 15 1990 Begin modifications for LRU algorithm in the *;
;* (alpha 0) RIF cache. 3rd parm on cmd line sets number *;
;* of entries in the cache, which is allocated *;
;* using INT 21, Function 48h. The cache *;
;* routines are modified to handle the new addr *;
;* mode for accessing the table. *;
;* *;
;* Jan 16 1990 Adding time mark info to SA_table structure. *;
;* (alpha 1) add_entry initializes t_mark *;
;* loc_entry refreshes t_mark when match found *;
;* add_entry uses LRU slot in table when slots *;
;* are all in use. *;
;* *;
;* Jan 18 1990 Updated the program documentation to reflect *;
;* the operation of the RIF cache. *;
;* *;
;* Version 1.C Add code for compatibility with Release 6 of *;
;* Mar 18 1990 Clarkson drivers, including TERMINATE call. *;
;* *;
;* Version 1.D Fix bug that prevents get_address from *;
;* returning adapter 1's hardware address. *;
;* *;
;* *;
;* Version 1.F Modified to coexist with other LAN software *;
;* 25.06.1991 (MS LAN Manager, IBM LAN Support ....) by *;
;* Antero Koskinen, Nokia Data Systems Oy, *;
;* Finland (anterok@xerver.data.nokia.fi) *;
;*****************************************************************************;
version equ 15h ; Version F = 15h
include defs.asm
debug = 0 ; set 1 for IRM marks on RX
alpha = 0 ; ALPHA Test Version = 0
alpha_ver = 1 ; Which ALPHA Version...
hrs24 = 1573040 ; ticks in 24 hour day
toke_vect = 5Ch ; LAN Support Pgm Vector
toke_wait = 0FFh ; completion code wait status
pool_size = 512 ; 8K space for buffer pool area
num_rcv_buff = 2 ; <2 defaults to 8
recv_size = 1536 ; max size of card recieve buffer
tran_size = 1536 ; max size of transmit buffer
STATION_ID = 0 ; ; talk using direct station
RECV_OPTIONS = 0C0h ; contiguous mac/data in bufs
open_cmd = 3h ; LAN Support OpCodes
interrupt_cmd = 0h
initialize_cmd = 20h
close_cmd = 4h
modify_cmd = 1h
restore_cmd = 2h
trans_dir_cmd = 0Ah
free_ccb_cmd = 27h
recv_can_cmd = 29h
open_recv_cmd = 28h
get_status_cmd = 21h
SA_table_size = 32 ; default size of the RIF cache
SA_min_size = 2 ; minimum size
SA_max_size = 1024 ; maximum size
LLC_AC = 10h ; access control LLC
LLC_FC = 40h ; frame control LLC
LLC_SSAP_DSAP = 0AAAAh ; reversed for network <grin>
LLC_CON = 03h
MAC_hdr_size = 22 ; MAC+LLC+SNAP header length
not_SA_mask = 7Fh
SA_mask = 80h
RIF_size_mask = 1Fh
RIF_dir_bit = 80h
broadcast_byte = 0FFh ; broadcast is FF,FF,FF,FF,FF,FF
ARP_type = 0608h ; reversed for network order
ARP_Eth_hwr = 0100h ; reversed for network order
ARP_Tok_hwr = 0600h ; reversed for network order
ARP_packet_size= 28 ; fixes Ethernet assumption...
phony_RIF = 2082h ; used for bridges...
LLC_info_size = 8 ; LLC (3) + SNAP(5) = 8
mark = 0F90h ; marker debug pos on screen 25
marker macro st,nd
IF debug NE 0 ; do marker if debug <> 0
pushf ; show 2 char marker on
push es ; 25th line, 1st column
push ax
mov ax,0B800h
mov es,ax
mov al,'&st&'
mov byte ptr es:[mark],al
mov al,byte ptr es:[mark+1] ; get color value
inc al
and al,0Fh
or al,1
mov byte ptr es:[mark+1],al ; advance it to show activity
mov al,'&nd'
mov byte ptr es:[mark+2],al
mov al,byte ptr es:[mark+3]
inc al
and al,0Fh
or al,1
mov byte ptr es:[mark+3],al
pop ax
pop es
popf
ENDIF
endm
call_token macro ccb
;--------------------------------------;
; loads address of CCB in ES:BX, then ;
; calls the Token Ring Interface. ;
;--------------------------------------;
mov ax,cs
mov es,ax
mov bx,offset &ccb&
int toke_vect
endm
call_wait macro
local wait_loop
;---------------------------------------;
; assumes ES:BX points to a CCB. Waits ;
; for a pending command to terminate. ;
;---------------------------------------;
wait_loop:
mov al,es:[bx+2]
cmp al,toke_wait
je wait_loop
endm
ticks macro
;---------------------------------------;
; get system timer ticks in CX:DX ;
;---------------------------------------;
mov ah,0
int 1Ah
endm
set_ptr macro dest,addr
;---------------------------------------;
; loads a far pointer with a near ;
; address offset and CS: ;
;---------------------------------------;
mov ax,offset &addr&
mov word ptr [&dest&],ax
mov ax,cs
mov word ptr [&dest&+2],ax
endm
print$ macro string
;---------------------------------------;
; sends $ terminated string to screen ;
;---------------------------------------;
mov ah,9
mov dx,offset &string& ; print $ terminated string
int 21h
endm
clr_struc macro name
;---------------------------------------;
; clear all bytes of the named struc ;
; to zero. Useful for Token calls. ;
;---------------------------------------;
mov cx,SIZE &name& ; uses ax, es:di, cx
mov ax,ds
mov es,ax
mov di,offset &name&
xor al,al
cld
rep stosb ; set all elements to 0
endm
rdupb macro l,n
&l& db ?
rept &n&-1
db ?
endm
endm
ccb_blk struc ; CCB used for local token ring calls.
adapter db ? ; adapter 0 or 1
command db ? ; command code
returncode db ? ; command completion code
work db ? ; scratch
pointer dd ? ; queue pointer
complt dd ? ; command complete appendage
parms dd ? ; pointer to CCB parameter table
ccb_blk ends
init_parms struc ; parameters for DIR_INITIALIZE
bring_ups dw ? ; result of bring up tests
sram_addr dw ? ; shared ram address
reserved dd ? ; not used...
chk_exit dd ? ; adapter check exit
status dd ? ; ring status exit
error dd ? ; PC error exit
init_parms ends
o_parms struc ; ccb parms for DIR_OPEN
adapt dd ? ; ptr to adapter parms
direct dd ? ; ptr to direct parms
dlc dd ? ; ptr to dlc parms
msg dd ? ; ptr to msg parms
o_parms ends
ada_blk struc ; adapter open parms table format
err_code dw ? ; open errors detected
options dw ? ; various options
node_addr dd ? ; node address ( 4 bytes here + )
dw ? ; rest of node address ( 2 here )
group_add dd ? ; group address
func_add dd ? ; functional address
rcv_buff dw ? ; number of receive buffers
rcv_len dw ? ; receive buffer length
dhb_len dw ? ; length of transmit buffers
hold_buf db ? ; number of tx buffers
db ? ; reserved
lock_code dw ? ; lock code
id_addr dd ? ; address of id code
ada_blk ends
dir_blk struc ; dir interfce open parms table format
buf_size dw ? ; size of direct station buffer
pool_blks dw ? ; number of 16 byte blocks in buff pool
pool_addr dd ? ; address of direct station buffer pool
chk_exit dd ? ; the rest can be 0 (defaults) for now
stat_exit dd ? ; ring status appendage pointer
err_exit dd ? ; PC error exit
work_addr dd ? ; work area segment value
len_req dw ? ; work area length requested
len_act dw ? ; actual length obtained
dir_blk ends
dlc_blk struc ; dlc interface open parms table format
max_sap db ? ; max number of saps
max_sta db ? ; max number of stations
max_gsap db ? ; max group saps
max_gmem db ? ; max members per group
t1_tick1 db ? ; DLC timer t1 interval
t2_tick1 db ? ; DLC timer t2 interval
TI_tick1 db ? ; DLC timer TI interval
t1_tick2 db ? ; DLC timer t1 group 2
t2_tick2 db ? ; DLC timer t2 group 2
TI_tick2 db ? ; DLC timer TI group 2
dlc_blk ends
mod_blk struc ; modify open parms parameter block
buf_size dw ? ; size of SAP buffers
pool_blks dw ? ; length in 16-byte, of buffer pool
pool_adrs dd ? ; address of direct interface buf pool
chkt_exit dd ? ; appendage, adapter check
stat_exit dd ? ; appendage, ring status
err_exit dd ? ; appendage, PC error exit
new_opts dw ? ; new options (wrap is ignored)
mod_blk ends
tx_blk struc ; transmit.dir.frame parameter block
station dw ? ; defines station sending data
trans_fs db ? ; * stripped FS field (returned)
rsap db ? ; RSAP (remote sap value)
queue_1 dd ? ; address of TX queue 1
queue_2 dd ? ; address of TX queue 2
buf_len_1 dw ? ; length of buffer 1
buf_len_2 dw ? ; length of buffer 2
buffer_1 dd ? ; address of the first transmit buffer
buffer_2 dd ? ; address of the second transmit buffer
tx_blk ends
free_blk struc ; buffer.free parameters
st_id dw ? ; station id
buf_left dw ? ; returns number of buffers left
resrvd dd ? ;
first_buf dd ? ; address of 1st buffer to free
free_blk ends
get_blk struc ; buffer.get parameters
stn_id dw ? ; station id
buffr_lef dw ? ; buffers left
buff_get db ? ; number of buffers to get
resrv1 db ? ; 3 bytes not used
resrv2 db ?
resrv3 db ?
frst_buff dd ? ; address of buffer obtained
get_blk ends
rx_blk struc ; receive parms
id dw ? ; station id
user_len dw ? ; size of user space in buffer
receiver dd ? ; appendage for received data
first_bf dd ? ; pointer to 1st buffer
opts db ? ; receive options
rx_blk ends
status_blk struc ; parameter table for dir.status
encoded_addr dw ? ; adapters permanent ring address
dd ?
node_adrs dw ? ; ring address set by open
dd ?
group_adrs dd ?
func_adrs dd ?
REPT 16
db ?
ENDM
REPT 3
dd ?
ENDM
dw ?
status_blk ends
mac_header struc ; token ring mac header format
AC db ? ; access control byte
FC db ? ; frame control byte
rdupb dest,EADDR_LEN
rdupb source,EADDR_LEN
dsap db ? ; LLC dsap
ssap db ? ; LLC ssap
control db ? ; control byte
ptype db ?
db ? ; SNAP header
db ?
ethtype dw ? ; EtherType
rif dw ? ; optional RIF information
REPT 8 ; segment information
dw ? ; this is not its real position.
ENDM ; this is a variable length field...
mac_header ends
SA_blk struc
rdupb s_addr,EADDR_LEN
RCF db ?
db ?
route dw ?
REPT 7
dw ?
ENDM ?
t_mark dd ? ; LRU time marker...
SA_blk ends
ether_hdr struc ; ethernet header format
rdupb ether_dest,EADDR_LEN
rdupb ether_src,EADDR_LEN
ether_type dw ?
ether_hdr ends
first_buffer struc ; Token receive 1st buffer
next_buffer dd ? ; ptr to next buffer
xx1 dw ?
data_size dw ? ; size of user data
REPT 12
db ?
ENDM
user_data db ?
first_buffer ends
user_data2 = 12 ; 2nd buffer slightly different
;=============================================================================;
;======================= START OF PROGRAM CODE ===============================;
;=============================================================================;
code segment word public
assume cs:code, ds:code
Token_address db EADDR_LEN dup (0) ; holds my address after init.
ccb ccb_blk <> ; scratch CCB
free_ccb ccb_blk <>
tx_parms tx_blk <> ; transmit.dir.frame parms
iparms init_parms <> ; init parms
pool_buff db (pool_size+1)*16 dup (?); buffer pool
free_parms free_blk <> ; buffer.free parameters
get_parms get_blk <> ; buffer.get parameters
rx_ccb ccb_blk <> ; receive CCB
rx_parms rx_blk <> ; receive parms
id_code db 18 dup (0) ; phony product id code
; (a real space saver...)
my_open db 0 ; set to 1 if we opened the adapter
ada_parm ada_blk <0,0,0,0,0,0,num_rcv_buff,recv_size,tran_size,1,0,0,0>
dir_parm dir_blk <0,pool_size,0,0,0,0,0,0,0>
dlc_parm dlc_blk <0,0,0,0,0,0,0,0,0,0>
init_parm o_parms <0,0,0,0>
initccb ccb_blk <0,0,0,0,0,0,0>
toke_status status_blk <>
modparms mod_blk <0,pool_size,0,0,0,0,0>
modccb ccb_blk < 0,modify_cmd,0,0,0,0,0>
lan_header mac_header <LLC_AC,LLC_FC>
; SA RIF table has 1 entry in it by default, for the broadcast address.
;
SA_index dw 1
SA_size dw SA_table_size ; size of table
dw 0 ; parsed from cmd line
SA_delta dw 0 ; delta t for LRU find
dw 0
SA_ord dw 0 ; ordinal for LRU entry
memory_needed dw 0 ; scratch for memory calculation
dir_interrupt proc
;---------------------------------------;
; Entry: token_card (0 or 1) ;
; Exit: AX = CCB return code ;
;---------------------------------------;
clr_struc ccb ; initialize CCB
mov ax,token_card
mov [ccb.adapter],al
mov al,interrupt_cmd
mov [ccb.command],al
call_token ccb ; call the interface
call_wait ccb ; wait for completion
xor ah,ah
mov al,[ccb.returncode] ; return the result in AX
ret
dir_interrupt endp
dir_initialize proc
;---------------------------------------;
; Entry: token_card (0 or 1) ;
; Exit: ;
; Ah = bring up return code ;
; Al = ccb return code ;
;---------------------------------------;
clr_struc ccb ; clear ccb
clr_struc iparms ; clear init parms (defaults)
mov ax,token_card ; assign parameters
mov [ccb.adapter],al
mov al,initialize_cmd ; command....
mov [ccb.command],al
set_ptr ccb.parms,iparms ; link to init parms
call_token ccb ; call the interface
call_wait ccb ; wait for completion
mov ah,byte ptr iparms.bring_ups
mov al,[ccb.returncode]
ret
dir_initialize endp
dir_open_adapter proc
;---------------------------------------;
; Entry: token_card (0 or 1) ;
; Exit: AX = CCB return code ;
;---------------------------------------;
mov ax,token_card ; get adapter number
mov [initccb.adapter],al
mov al,open_cmd
mov [initccb.command],al ; 03h open_adapter command
set_ptr ada_parm.id_addr,id_code
set_ptr dir_parm.pool_addr,pool_buff
set_ptr init_parm.adapt,ada_parm
set_ptr init_parm.direct,dir_parm
set_ptr init_parm.dlc,dlc_parm
set_ptr initccb.parms,init_parm
xor al,al
mov [initccb.returncode],al
call_token initccb ; call the interface
call_wait initccb ; wait for completion
xor ah,ah
mov al,[initccb.returncode]
ret
dir_open_adapter endp
dir_close_adapter proc
;---------------------------------------;
; Entry: token_card (0 or 1) ;
; Exit: AX = CCB return code ;
;---------------------------------------;
clr_struc ccb ; clear CCB
mov ax,token_card ; initialize local CCB
mov [ccb.adapter],al
mov al,close_cmd ; close command
mov [ccb.command],al
call_token ccb ; call the interface
call_wait ccb ; wait for completion
xor ah,ah
mov al,[ccb.returncode] ; return the result
ret
dir_close_adapter endp
dir_modify_open proc
;---------------------------------------;
; Entry: token_card (0 or 1) ;
; Exit: AX = CCB return code ;
;---------------------------------------;
mov ax,token_card ; get adapter number
mov [modccb.adapter],al ; command is a constant in ccb
set_ptr modparms.pool_adrs,pool_buff
set_ptr modccb.parms,modparms
xor al,al
mov [modccb.returncode],al
call_token modccb ; call the interface
call_wait modccb ; wait for completion
xor ah,ah
mov al,[modccb.returncode]
ret
dir_modify_open endp
dir_restore_open proc
;---------------------------------------;
; Entry: token_card (0 or 1) ;
; Exit: AX = CCB return code ;
;---------------------------------------;
clr_struc ccb ; initialize CCB
mov ax,token_card
mov [ccb.adapter],al
mov al,restore_cmd ; dir.restore.open.parms
mov [ccb.command],al
call_token ccb ; call the interface
call_wait ccb ; wait for completion
xor ah,ah
mov al,[ccb.returncode] ; return the result in AX
ret
dir_restore_open endp
transmit_dir_frame proc
;---------------------------------------;
; Entry: token_card (0 or 1) ;
; ;
; Stack: ;
; sp+14 dw [usr seg] ;
; sp+12 dw [usr ofs] ;
; sp+10 dw [usrsize] ;
; sp+8 dw [hdr seg] ;
; sp+6 dw [hdr ofs] ;
; sp+4 dw [hdrsize] ;
; sp+2 dw [ret ofs] ;
; sp+0 dw [ bp ] ;
; ;
; Exit: ;
; Ah = stripped FS field ;
; al = CCB return code ;
;---------------------------------------;
trans_frame struc ; transmit_dir_frame parms
_x_bp dw ? ; old bp register
_x_ret_ofs dw ? ; near return address
header_size dw ? ; MAC header size
llc_header dd ? ; address of header
user_dsize dw ? ; user data size
user_daddress dd ? ; user data address
trans_frame ends
push bp
mov bp,sp
mov ax,cs
mov ds,ax
clr_struc ccb ; zero the CCB
clr_struc tx_parms ; zero parameters
mov ax,token_card ; initialize local CCB
mov [ccb.adapter],al
mov al,trans_dir_cmd ; transmit.dir.frame
mov [ccb.command],al
;
; Set up transmit parameters, and link them to
; the CCB...
;
mov ax,offset tx_parms
mov word ptr [ccb.parms],ax
mov ax,cs
mov word ptr [ccb.parms+2],ax
;
mov ax,STATION_ID
mov word ptr [tx_parms.station],ax
mov ax,[bp][user_dsize]
mov word ptr [tx_parms.buf_len_2],ax
mov ax,word ptr [bp][user_daddress]
mov word ptr [tx_parms.buffer_2],ax
mov ax,word ptr [bp][user_daddress+2]
mov word ptr [tx_parms.buffer_2+2],ax
mov ax,[bp][header_size]
mov word ptr [tx_parms.buf_len_1],ax
mov ax,word ptr [bp][llc_header]
mov word ptr [tx_parms.buffer_1],ax
mov ax,word ptr [bp][llc_header+2]
mov word ptr [tx_parms.buffer_1+2],ax
call_token ccb ; call the interface
call_wait ccb ; wait for completion
mov ah,[tx_parms.trans_fs]
mov al,[ccb.returncode]
pop bp
ret (SIZE trans_frame)-4 ; (forget bp and ret address)
transmit_dir_frame endp
buffer_free proc
;---------------------------------------;
; Entry: ;
; sp+4 [ seg 1st buffer ] ;
; sp+2 [ ofs 1st buffer ] ;
; sp+0 [ bp ] ;
; ;
; Exit: AX = CCB return code ;
;---------------------------------------;
mov ax,cs
mov ds,ax
push bp
mov bp,sp
clr_struc free_ccb
clr_struc free_parms
mov ax,token_card ; initialize local CCB
mov [free_ccb.adapter],al
mov al,free_ccb_cmd ; buffer.free
mov [free_ccb.command],al
mov ax,offset free_parms
mov word ptr [free_ccb.parms],ax
mov ax,cs
mov word ptr [free_ccb.parms+2],ax
;
; Load free_parms to release buffer
;
mov ax,STATION_ID
mov word ptr [free_parms.st_id],ax
mov ax,word ptr [bp][4]
mov word ptr [free_parms.first_buf],ax
mov ax,word ptr [bp][6]
mov word ptr [free_parms.first_buf+2],ax
call_token free_ccb ; call the interface
xor ah,ah
mov al,[free_ccb.returncode]; return the result in AX
pop bp
ret 4
buffer_free endp
recv_cancel proc
;---------------------------------------;
; Entry: token_card (0 or 1) ;
; ;
; Exit: ;
; AX = CCB return code ;
; ;
;---------------------------------------;
mov ax,token_card ; initialize local CCB
mov [ccb.adapter],al
mov al,recv_can_cmd ; receive.cancel
mov [ccb.command],al
xor ax,ax ; word/bytes set to 0
mov [ccb.returncode],al
mov [ccb.work],al
mov word ptr [ccb.pointer],ax
mov word ptr [ccb.pointer+2],ax
mov word ptr [ccb.complt],ax
mov word ptr [ccb.complt+2],ax
mov word ptr [ccb.parms+2],ax
mov ax,STATION_ID
mov word ptr [ccb.parms],ax
call_token ccb ; call the interface
call_wait ccb ; wait for completion
xor ah,ah
mov al,[ccb.returncode] ; return the result in AX
ret
recv_cancel endp
open_receive proc
;---------------------------------------;
; Entry: token_card (0 or 1) ;
; ;
; Stack: ;
; sp+6 dw [ret ofs] ;
; sp+4 dw [ bp ] ;
; sp+2 dw [ ds ] ;
; sp+0 dw [ es ] ;
; ;
; Exit: ;
; AX = CCB return code ;
;---------------------------------------;
mov ax,cs
mov ds,ax
clr_struc rx_ccb
clr_struc rx_parms ;
mov ax,token_card ; initialize local CCB
mov [rx_ccb.adapter],al
mov al,open_recv_cmd ; receive
mov [rx_ccb.command],al
mov ax,offset recv_complt
mov word ptr [rx_ccb.complt],ax
mov ax,cs
mov word ptr [rx_ccb.complt+2],ax
;
; Link receive parameters table
;
mov ax,offset rx_parms
mov word ptr [rx_ccb.parms],ax
mov ax,cs
mov word ptr [rx_ccb.parms+2],ax
mov ax,STATION_ID
mov word ptr [rx_parms.id],ax
mov al,RECV_OPTIONS
mov rx_parms.opts,al
mov ax,offset _receiver
mov word ptr [rx_parms.receiver],ax
mov ax,cs
mov word ptr [rx_parms.receiver+2],ax
;
; Note: The receive request is submitted, but it doesn't 'complete'
; here. So DON'T wait for a completion code!
;
call_token rx_ccb ; call the interface
xor ah,ah
mov al,[rx_ccb.returncode] ; return the result
ret
open_receive endp
recv_complt proc
;
; This procedure is an interrupt routine called by the Token Card
; when receive completion occurs after an error. All it should have
; to do is resubmit the receive request, then exit.
;
pushf
push ax
push bx
push cx
push dx
push si
push di
push ds
push es
push bp
sti
marker E,R
call open_receive ; restart communications
pop bp
pop es
pop ds
pop di
pop si
pop dx
pop cx
pop bx
pop ax
popf
iret
recv_complt endp
recv_frame struc ; stack frame for receiver
RIF_size dw ? ; size of RIF in packet.
user_buff dd ? ; pointer to users buffer
user_size dw ? ; size of buffer needed/used
_BP dw ? ; register set on stack
_ES dw ?
_DS dw ?
_DI dw ?
_SI dw ?
_DX dw ?
_CX dw ?
_BX dw ?
_AX dw ?
recv_frame ends
_receiver proc
;
; This interrupt procedure is called when the Token Ring
; card has data.
;
; On entry, ds:si points to the CCB
; es:bx points to the receive first_buffer in the chain.
;
;
pushf ; save CPU environment
push ax
push bx
push cx
push dx
push si
push di
push ds
push es
push bp
push ax ; local variables: size of receive data
push ax ; segment of user supplied buffer
push ax ; offset of user supplied buffer
push ax
mov bp,sp ; set stack frame reference
sti ; enable further int activity
marker R,X
;
; If the source address is mine, ignore the transmission!
;
mov ax,cs
mov ds,ax
mov si,offset Token_address
mov di,bx
add di,user_data+source ; ds:si -> token address
; es:di -> pkt
mov cx,EADDR_LEN
push word ptr es:[di] ; save msb of address
mov al,es:[di]
and al,not_SA_mask ; drop SA indicator
mov es:[di],al ; fix the bit during compare
;
; patch to fix direction bit problem...
;
cld
repe cmpsb ; do string compare now
jne not_mine
mov di,bx
add di,user_data+source
pop word ptr es:[di] ; restore token address
jmp drop_buffer ; from me, ignore it!
; es:bx -> 1st receive buffer
not_mine:
mov di,bx
add di,user_data+source
pop word ptr es:[di] ; save MSB of source address
xor ax,ax
mov cx,ax
mov word ptr [bp][RIF_size],ax; zero RIF size value
get_size:
mov ax,es
or ax,bx
je got_size
add cx,word ptr es:[bx][data_size]
push word ptr es:[bx][next_buffer]
push word ptr es:[bx][next_buffer+2]
pop es ; ************************
pop bx ; ************************
jmp get_size
got_size:
sub cx,LLC_info_size ; adjust size for Token
mov ax,word ptr [bp][_ES]
mov es,ax
mov bx,word ptr [bp][_BX] ; get buffer address
mov al,es:[bx][user_data+source]
and al,SA_mask ; if SA, adjust total
je got_no_fix
;
; How big is the RIF?
;
mov ax,word ptr es:[bx][user_data+source+EADDR_LEN]
and ax,RIF_size_mask
mov word ptr [bp][RIF_size],ax
;
; Take away size of RIF. Upper level doesn't get it.
;
sub cx,ax ; subtract RIF size
got_no_fix:
;
; Min Ethersize is RUNT, so check it first, round up if necessary
;
cmp cx,RUNT
jge no_adjust_cx
mov cx,RUNT
no_adjust_cx:
mov word ptr [bp][user_size],cx; save size of receive data
;
; Call recv_find to determine if the receiver wants the data,
; and where it should be stored.
;
mov ax,word ptr [bp][_ES] ; reload segment/offset
mov es,ax
mov di,word ptr [bp][_BX] ; points to E-type in Token
add di,40 ; assumes Buffer 1 format,
add di,word ptr [bp][RIF_size]; RIF size added now...
;
; if ARP type, convert hardware address space value back to Ethernet...
;
mov ax,word ptr es:[di] ; -> EtherType in SNAP
cmp ax,ARP_type ; ARP packet?
jne not_rx_arp
mov ax,ARP_Eth_hwr
mov word ptr es:[di][2],ax ; fix 1st field of data
not_rx_arp:
mov dl,BLUEBOOK
call recv_find ; es:di -> Snap E-Type, CX = data size
mov word ptr [bp][user_buff],di
mov ax,es
mov word ptr [bp][user_buff+2],ax
or ax,di
jne do_copy
jmp drop_buffer ; if ptr is 0, doesn't want it!
;
; Copy Token Ring data to users Ethernet format receive buffer.
;
do_copy:
;
; Since the upper level wants it, better keep the RIF info in case we
; want to send a return message.
;
mov ax,word ptr [bp][_ES]
mov ds,ax
mov si,word ptr [bp][_BX]
add si,user_data+source ; 1st byte of source address
call add_entry ; do table maintenance
;
; Copy data to the users buffer
;
mov di,word ptr [bp][user_buff]; Ethernet destination buffer
mov ax,word ptr [bp][user_buff+2]
mov es,ax
mov si,word ptr [bp][_BX] ; Token Ring Source buffer
mov bx,si
mov ax,word ptr [bp][_ES]
mov ds,ax
add si,user_data ; offset to user data
;
; ds:si points to 1st token buffer
; es:di points to ethernet format buffer
; 1. Copy Token/Ether dest/source field to users buffer
; after stripping off the SA bit in the source address.
mov al,byte ptr ds:[si+source];****************
and al,07Fh ;***** NEW ******
mov byte ptr ds:[si+source],al;****************
mov cx,EADDR_LEN*2 ; 2 address fields
add si,2 ; offset to dest field
cld
rep movsb
add si,LLC_info_size-2 ; assume no RIF,
add si,word ptr [bp][RIF_size]; compensate for RIF
movsw ; get ethertype
mov cx,[bx][data_size] ; get length of data
sub cx,MAC_hdr_size ; drop MAC header stuff
sub cx,[bp][RIF_size] ; compensate for RIF
copy_buffer:
cld
rep movsb ; copy rest of data to Ether..
push word ptr [bx][next_buffer]
push word ptr [bx][next_buffer+2]
pop ds
pop si
mov bx,si ; bx is base of buffer
add si,user_data2 ; si offsets to user data
mov cx,[bx][data_size] ; length of user data
mov ax,ds
or ax,bx ; NULL pointer?
jne copy_buffer ; no, keep copying...
;
; Tell Upper layer I copied the data into his buffer...
;
mov si,word ptr [bp][user_buff]
mov ax,word ptr [bp][user_buff+2]
mov ds,ax
mov cx,word ptr [bp][user_size]
call recv_copy
;
; _ES:_BX points to 1st receive buffer, drop it, then exit
;
drop_buffer:
mov ax,word ptr [bp][_ES] ; tell Token, drop buffer
mov bx,word ptr [bp][_BX]
push ax
push bx
call buffer_free ; seg:offs of 1st buff on stack
pop ax ; vacuum local variables off
pop ax ; the stack
pop ax
pop ax
pop bp
pop es
pop ds
pop di
pop si
pop dx
pop cx
pop bx
pop ax
popf
marker r,x
iret
_receiver endp
comp_adr proc
;
; Compare two token address values, set flags without affecting any
; other registers. JE or JNE to test result.
;
push si
push di
push cx
cld
mov cx,EADDR_LEN
repe cmpsb
pop cx
pop di
pop si
ret
comp_adr endp
make_adr proc
;
; Given CX as an ordinal (1..n) into the RIF_cache, build the address
; in ES:DI
;
push ax
push cx
dec cx
xor di,di
cmp cx,0
je make_adr1
make_adr0:
add di,SIZE SA_blk ; build index into SA_table
loop make_adr0
make_adr1:
mov ax,cs ; segment of table
mov es,ax
add di,offset RIF_cache ; + offset to base of table
pop cx
pop ax
ret
make_adr endp
add_entry proc
;
; DS:SI -> Token Address, make an entry in the SA routing table
;
mov cx,EADDR_LEN ; don't add broadcasts to table
push si ; leave the default intact
cld
add_entry0:
lodsb ; Broadcast?
cmp al,broadcast_byte
loope add_entry0
pop si
je add_done ; yes...
mov al,ds:[si] ; is it a source route address?
and al,SA_mask
je add_done
;
; Is it in the table?
call loc_entry
jc add_done ; c = 1, its in the table.
;
; if its not in the table, try to put it in a 'new' slot...
;
mov cx,word ptr cs:[SA_index]
cmp cx,word ptr cs:[SA_size]
jne lotsa_room ; room in table, make flat entry
;
; If no new slots available, determine LRU entry and overwrite it...
;
push ds ; save initial pointer
push si
call find_lru ; returns cx ordinal into table
pop si ; restore initial pointer
pop ds
jmp do_entry
;
; Update entry pointer, overwrite a new slot in the table...
;
lotsa_room:
inc cx
mov word ptr cs:[SA_index],cx; advance the table index
; before entry is made, the broadcast bit must be cleared so bridges
; will leave the segment values alone.
do_entry:
mov al,byte ptr ds:[si+EADDR_LEN]
and al,07Fh ; clear broadcast bit
mov byte ptr ds:[si+EADDR_LEN],al
call make_adr ; build destination address
push si
push di
push es
mov cx,SIZE SA_blk
cld
rep movsb ; copy RIF into table
pop es
pop di
pop si
;
; Put time stamp on the new entry for LRU algorithm
;
ticks ; cx:dx = ticks count
mov word ptr es:[di+t_mark],dx
mov word ptr es:[di+t_mark+2],cx
add_done:
ret
add_entry endp
find_lru proc
;
; locates oldest entry in the RIF_cache, returns the ordinal number in
; CX. The first entry is NEVER chosen because it contains the broadcast
; route predefined in the table!
;
; CX = 2 .. cs:[SA_size] ( range to be searched )
;
; SA_delta dword contains time difference for last one checked
; SA_ord word contains the ordinal of the least recently used
;
xor ax,ax ; zero search variables
mov word ptr cs:[SA_delta],ax
mov word ptr cs:[SA_delta+2],ax
mov word ptr cs:[SA_ord],ax
mov cx,2 ; 1st entry is NEVER touched!
find_loop:
call make_adr ; es:di -> current entry
push cx ; save index
ticks ; cx:dx = current ticks
sub cx,word ptr es:[di+t_mark+2]; ticks = mark
sbb dx,word ptr es:[di+t_mark]
;
; if the result < 0, then ticks went past midnight. Add 24 hrs in
; ticks to get the real delta t.
;
jge _no_fix
add cx,((hrs24 shr 16) and 0ffffh); longint to fix delta t
adc dx,(hrs24 and 0ffffh) ; add 24 hours in ticks to
_no_fix:
;
; If the result is greater than the stored SA_delta, replace it with
; this entry, then continue the loop...
;
push cx ; save hi/low delta t result
push dx
sub cx,word ptr cs:[SA_delta+2]
sbb dx,word ptr cs:[SA_delta]
jl _no_replace
;
; replace SA_ord and SA_delta with entry that has been around longer
;
pop cs:[SA_delta] ; pull lo/hi delta t result
pop cs:[SA_delta+2]
pop cx ; get ordinal...
mov word ptr cs:[SA_ord],cx ; replace SA_ord...
jmp _next_find
_no_replace:
pop cx
pop cx
pop cx
_next_find:
inc cx
cmp cx,word ptr cs:[SA_size]
jle find_loop
jmp _find_exit
_find_exit:
mov cx,SA_ord ; return ordinal of LRU
ret
find_lru endp
loc_entry proc
;
; DS:SI -> Token Address, locate entry in the SA routing table
; ES:DI -> SA information in table, if carry is set.
;
mov cx,word ptr cs:[SA_index]; any entries in table?
cmp cx,0
je loc_done
loc_entry0:
call make_adr ; build address into table
call comp_adr ; compare Token Addresses
je loc_found ; if matches, in table
loop loc_entry0
loc_done:
clc
ret
loc_found:
; ES:DI points to matching entry
ticks ; cx:dx = ticks value for
mov word ptr es:[di+t_mark],dx; refresh of existing
mov word ptr es:[di+t_mark+2],cx; entry...
stc
ret
loc_entry endp
;==============================================================================
;
;=================== DRIVER CODE =============================================
;
;==============================================================================
;
;
; Token Ring Card number, parsed from command line
;
token_card dw 0 ; default adapter number 0
dw 0 ; this prevents type error.
toke_ad_name db "Adapter (0 or 1) ",'$'
toke_sa_name db " RIF Cache Size: ",'$'
dir_open_mode db 0 ; set <> 0 if modify_open used
msg_initialize db " INIT: Initializing the adapter...",CR,LF,'$'
msg_opening db " Opening the adapter...",CR,LF,'$'
msg_complete db " IBMTOKEN - Initialization complete.",CR,LF,'$'
msg_modifying db " Creating direct buffer pool...",CR,LF,'$'
msg_bad_adapter db "ERROR: adapter must be 0 or 1.",CR,LF,'$'
no_mem_cache db "ERROR: RIF_cache value out of range!",CR,LF
msg_bad_init db "ERROR: Initialization Failed.",CR,LF
db " Installation aborted!",CR,LF,'$'
msg_receiving db " Starting receiver process...",CR,LF,'$'
public int_no
int_no db 0,0,0,0 ;must be four bytes long for get_number.
public driver_class, driver_type, driver_name, driver_function, parameter_list
driver_class db BLUEBOOK,0 ;from the packet spec
driver_type db 1 ;from the packet spec
driver_name db 'IBMTokenR',0 ;name of the driver.
driver_function db 2
parameter_list label byte
db 1 ;major rev of packet driver
db 9 ;minor rev of packet driver
db 14 ;length of parameter list
db EADDR_LEN ;length of MAC-layer address
dw GIANT ;MTU, including MAC headers
dw MAX_MULTICAST * EADDR_LEN;buffer size of multicast addrs
dw 0 ;(# of back-to-back MTU rcvs) - 1
dw 0 ;(# of successive xmits) - 1
dw 0 ;Interrupt # to hook for post-EOI
;processing, 0 == none,
public rcv_modes
rcv_modes dw 4 ;number of receive modes in our table.
dw 0,0,0,rcv_mode_3
sp_frame struc
__bp dw ?
u_size dw ?
u_data dd ?
u_snap dw ?
sp_frame ends
public as_send_pkt
; The Asynchronous Transmit Packet routine.
; Enter with es:di -> i/o control block, ds:si -> packet, cx = packet length,
; interrupts possibly enabled.
; Exit with nc if ok, or else cy if error, dh set to error number.
; es:di and interrupt enable flag preserved on exit.
as_send_pkt:
ret
public drop_pkt
; Drop a packet from the queue.
; Enter with es:di -> iocb.
drop_pkt:
assume ds:nothing
ret
public xmit
; Process a transmit interrupt with the least possible latency to achieve
; back-to-back packet transmissions.
; May only use ax and dx.
xmit:
assume ds:nothing
ret
public send_pkt
send_pkt:
;enter with ds:si -> packet, cx = packet length.
;exit with nc if ok, or else cy if error, dh set to error number.
assume ds:nothing
sti
marker T,X
;
; construct local stack frame
;
mov ax,word ptr ds:[si][ether_type]
push ax
push ds ; pointer to user data packet
mov ax,si
add ax,SIZE ether_hdr
push ax ; adjusted userdata pointer
sub cx,SIZE ether_hdr ; adjust size for send
push cx
push bp
mov bp,sp ; use sp_frame for reference
mov ax,cs ; set dest pointer to LLC header
mov es,ax
mov di,offset lan_header.dest
mov cx,EADDR_LEN*2 ; copy dest|source fields
cld
rep movsb
;
; ds:si -> dest address, locate it in the SA RIF table
;
mov ax,cs
mov ds,ax
mov si,offset lan_header.dest; building LAN header info here
; Set bit 7 of address, force lookup in table. If it is found, add RIF,
; otherwise, assume the local net.
mov al,byte ptr ds:[si]
or al,080h
mov byte ptr ds:[si],al
call loc_entry
jc send_pkt1 ; yes, copy out RIF information
;
; add the rest of the fields to the LLC header, and set the size
; for the transmit call.
;
mov al,byte ptr ds:[si] ; dest address 1st byte,
; lop off SA bit
and al,not_SA_mask
mov byte ptr ds:[si],al
mov al,byte ptr ds:[si][EADDR_LEN]; force U bit high
or al,080h
mov byte ptr ds:[si][EADDR_LEN],al
add si,EADDR_LEN*2 ; point after dest/source addrs.
mov ax,es
mov bx,ds
mov ds,ax
mov es,bx
xchg si,di
; addresses acquired from ARP default to broadcast mode, using phony
; RIF info so the bridge will pass the packet along.
;
mov ax,phony_RIF ; copy phony RIF to LLC buffer,
cld ; so 'local' can cross bridge..
stosw
jmp send_pkt2
send_pkt1:
;
; source/dest address need to be adjusted for routing.
;
mov cx,EADDR_LEN
push si
send_pkt3:
mov al,byte ptr ds:[si]
inc si
cmp al,broadcast_byte
loope send_pkt3
pop si
je send_pkt4 ; broadcast address?
mov al,byte ptr ds:[si] ; dest, lop off SA bit
and al,not_SA_mask
mov byte ptr ds:[si],al
send_pkt4:
mov al,byte ptr ds:[si][EADDR_LEN]
or al,SA_mask ; set SA bit for RIF
mov byte ptr ds:[si][EADDR_LEN],al
add si,EADDR_LEN*2 ; ds:si -> dest for RIF info.
add di,EADDR_LEN ; es:di -> RIF info, addr fld
mov bx,si ; keep RIF pos in LLC header
mov ax,word ptr es:[di] ; get rif info
and ax,RIF_size_mask ; get length of RIF
mov cx,ax
mov ax,es
mov dx,ds
mov ds,ax
mov es,dx
xchg si,di
cld
rep movsb
;
; Got RIF, fix direction bit.
;
mov al,es:[bx][1] ; RIF+1 = dir bit location
xor al,RIF_dir_bit ; change direction
mov es:[bx][1],al
send_pkt2:
;
; es:di -> target in LLC for the rest of the header,
; add LLC and SNAP information.
;
mov ax,LLC_SSAP_DSAP ; build LLC portion
stosw
mov al,LLC_CON
stosb
xor ax,ax ; 3 bytes for Ptype in SNAP
stosw
stosb
mov ax,word ptr [bp][u_snap]
stosw
;
; header is complete.
;
sub di,offset lan_header ; calculate size of LLC header
;
; stack parameters for Transmit
;
pop bp
mov ax,cs
mov ds,ax ; set ds for transmit entry
push ax
mov ax,offset lan_header
push ax
push di
;--------------------------------------------------------------------
; If Users data is an ARP packet, 0806 type, then the 1st field
; must be changed from 0001 to 0006 for Token Ring broadcast, or
; no one will respond. Funny, eh? Another thing. Since an ARP
; packet is smaller than the min size for Ethernet, the caller rounds
; up the size. I have to change it back, or some Token hosts won't
; ARP for me. The nerve!
;
push bp
mov bp,sp
mov ax,word ptr [bp][14] ; offset to ARP type on stack...
pop bp
cmp ax,ARP_type ; network byte order is backwards
jne not_tx_arp
;
; The first field of the ARP data has to be changed from 0001 to 0006
;
push bp ; use trans_frame
push bp ; dummy entry on stack...
mov bp,sp
mov ax,word ptr [bp][user_daddress+2]; addr of user data
mov es,ax
mov di,word ptr [bp][user_daddress]
mov ax,ARP_Tok_hwr
mov word ptr es:[di],ax ; change ARP type to 0006
mov ax,ARP_packet_size ; 28 bytes in an ARP packet
mov word ptr [bp][user_dsize],ax; reset users data size
pop bp ; pop fake return address
pop bp ; pop real bp
not_tx_arp:
call transmit_dir_frame ; send the packet
pop ax ; vacuum
clc
ret
public get_address
get_address:
;get the address of the interface.
;enter with es:di -> place to get the address, cx = size of address buffer.
;exit with nc, cx = actual size of address, or cy if buffer not big enough.
assume ds:code
;
push di
push es
push cx
mov ax,cs
mov ds,ax
clr_struc ccb
clr_struc toke_status
mov ax,token_card ; set adapter number
mov [ccb.adapter],al
mov al,get_status_cmd ; get status returns address
mov ccb.command,al
mov ax,offset toke_status
mov word ptr [ccb.parms],ax
mov ax,ds
mov word ptr [ccb.parms+2],ax
call_token ccb
call_wait ccb
mov si,offset toke_status.node_adrs
pop cx
pop es
pop di
cmp cx,EADDR_LEN ; got the room for it?
jb get_address_fail
cld
mov cx,EADDR_LEN
rep movsb
mov cx,EADDR_LEN
clc
ret
get_address_fail:
stc
ret
public set_address
set_address:
;enter with ds:si -> Ethernet address, CX = length of address.
;exit with nc if okay, or cy, dh=error if any errors.
assume ds:nothing
clc
ret
rcv_mode_3:
;receive mode 3 is the only one we support, so we don't have to do anything.
ret
public set_multicast_list
set_multicast_list:
;enter with es:di ->list of multicast addresses, cx = number of bytes.
;return nc if we set all of them, or cy,dh=error if we didn't.
mov dh,NO_MULTICAST
stc
ret
public get_multicast_list
get_multicast_list:
;return with nc, es:di ->list of multicast addresses, cx = number of bytes.
;return cy, NO_ERROR if we don't remember all of the addresses ourselves.
;return cy, NO_MULTICAST if we don't implement multicast.
mov dh,NO_MULTICAST
stc
ret
public reset_interface
reset_interface:
;reset the interface.
assume ds:code
ret
;called when we want to determine what to do with a received packet.
;enter with cx = packet length, es:di -> packet type, dl = packet class.
extrn recv_find: near
;called after we have copied the packet into the buffer.
;enter with ds:si ->the packet, cx = length of the packet.
extrn recv_copy: near
extrn count_in_err: near
extrn count_out_err: near
public recv
recv:
;called from the recv isr. All registers have been saved, and ds=cs.
;Upon exit, the interrupt will be acknowledged.
assume ds:code
ret
public terminate
terminate:
sti
call recv_cancel ; shut down call-backs
cmp my_open, word ptr 1
jne restore_parms
call dir_close_adapter ; close out the adapter
final_exit:
ret
restore_parms:
call dir_restore_open
jmp short final_exit
public recv_exiting
recv_exiting:
;called from the recv isr after interrupts have been acknowledged.
;Only ds and ax have been saved.
assume ds:nothing
ret
;=======================================================================;
;============================== RIF Cache ==============================;
;=======================================================================;
; The RIF_cache starts here. Code appearing after the RIF cache ;
; will be lost after initialization. It becomes part of the RIF ;
; cache area, or is released back to DOS. The program code and ;
; RIF_cache form a contiguous block in memory. The first entry ;
; in the cache is for the broadcast address. This entry is NEVER ;
; bumped from the cache! ;
;=======================================================================;
RIF_cache:
SA_blk <0ffh,0ffh,0ffh,0ffh,0ffh,0ffh,82h,0A0h,0>
public usage_msg
usage_msg db CR,LF
db "usage: IBMTOKEN <packet_int_no> <adapter> <RIF_cache>",CR,LF,LF
db "where: packet_int_no is the interrupt vector",CR,LF
db " adapter is adapter 0 or 1",CR,LF
db " RIF_cache is number of hosts in RIF cache",CR,LF,CR,LF
db " note: IBM (tm) LAN Support Program or similar DLC",CR,LF
db " interface for other TR adapters required.",CR,LF,'$'
public copyright_msg
copyright_msg db CR,LF,"Token Ring Driver (3C501 emulation) Version "
db '0'+majver,".",'0'+version,CR,LF
IF alpha NE 0
db "ALPHA TEST VERSION ",'0'+alpha_ver,CR,LF
ENDIF
db "portions -",CR,LF
db "Copyright 1989, Queens University",CR,LF
db "Computing and Communications Services",CR,LF
db "Written by Brian Fisher",CR,LF
db "Modified to run with MS LAN Manager/IBM LAN",CR,LF
db "Support Program by Antero Koskinen",CR,LF
IF debug NE 0
db "*** DEBUG VERSION ***",CR,LF
ENDIF
db LF,LF
db '$'
extrn set_recv_isr: near
;enter with si -> argument string, di -> wword to store.
;if there is no number, don't change the number.
extrn get_number: near
public parse_args
parse_args:
;
; si points to next argument of command line...
;
mov di,offset token_card ; next argument is card number
call get_number
jc _parse_exit
mov di,offset SA_size ; see if cache size ok...
call get_number
_parse_exit:
clc
ret
et_error:
; token adapter number out of range
;if we got an error,
print$ msg_bad_adapter
stc
ret
sa_error:
; RIF cache allocation problem
; if no memory for SA table,
print$ no_mem_cache
stc
ret
et_init_error:
call dir_close_adapter ; make sure adapter is closed
print$ msg_bad_init
stc
ret
public etopen
;
; Initialize the IBM Token Ring Adapter, determine memory requirements
; for the RIF_cache.
;
etopen:
mov ax,cs
mov ds,ax
assume cs:code, ds:code
mov ax,token_card ; check card parm for range
cmp ax,1
jg et_error
cmp ax,0
jl et_error ; less than zero?
mov ax,cs:[SA_size] ; is the requested RIF cache
cmp ax,SA_min_size ; size in range?
jl SA_error
cmp ax,SA_max_size
jg SA_error
mov bx,SIZE SA_blk ; multiply to get bytes needed
imul bx
add ax,(offset RIF_cache)+15; offset + round up value
adc dx,0
jne SA_error ; dx <> 0, way out of range!
mov cs:[memory_needed],ax ; bytes needed for code+RIF
; Note: If a memory allocation error occurs when this init routine
; returns, the system will crash because the call backs are already
; defined for LAN Support. I do a resize here, just to verify that
; it will work.
;
add ax,15
mov cl,4
shr ax,cl
mov bx,ax
mov ax,cs ; get segment
mov es,ax
mov ah,4Ah ; resize memory block
int 21h
jc SA_error ; c=1, error doing memory
do_init:
call dir_interrupt ; check if adapter open
cmp ax, 0 ; adapter open if retcode 0
je modify
print$ msg_initialize ; initialize the adapter
call dir_initialize
cmp ax,0
jne et_init_error
print$ msg_opening ; open the adapter
call dir_open_adapter
cmp ax,0
jne et_init_error
mov my_open, word ptr 1
jmp short no_init
modify:
print$ msg_modifying ; modify adapter open params
call dir_modify_open
cmp ax, 0
je no_init
jmp et_init_error
no_init:
print$ msg_receiving ; set up receive routines
call open_receive
cmp ax,0ffh
je init_ok
jmp et_init_error ; no receive open...
init_ok:
print$ msg_complete ; card ready to go
mov ax,cs
mov es,ax
mov ds,ax
mov di,offset Token_address
mov cx,EADDR_LEN
call get_address
mov dx,memory_needed ;tell caller how much memory I want...
clc
ret
public print_parameters
print_parameters:
ret
code ends
end
;******************************************************************************
;
;* End of file: IBMTOKEN.ASM *
;
;******************************************************************************